﻿

using IotContract.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IotClientService.Models.Hbc;
public class PlcReadBlockManager
{
    private Dictionary<string, List<PlcReadBlock>> _DicReadBlock = new Dictionary<string, List<PlcReadBlock>>();

    // 添加 ReadBlock 字典
    public void MakeReadBlock(int readMaximumSize, List<PlcReadWord> readWordInfoList)
    {
        _DicReadBlock.Clear();
        List<PlcReadWord> readWordInfoListAlign = (from readWordInfo in readWordInfoList
                                                    orderby readWordInfo.DBBlock, readWordInfo.MemoryType, readWordInfo.StartAddr, readWordInfo.ReadCount descending
                                                    select readWordInfo).ToList();
        PlcMemoryType currentProcMemoryType = PlcMemoryType.D;
        int currentDBBlock = 0;
        bool isProcessedMakeBlockFirstAddress = true;
        PlcReadBlock makeBlock = null;
        List<PlcReadBlock> currentReadBlockList = null;
        foreach (PlcReadWord readWordInfo2 in readWordInfoListAlign)
        {
            if (readWordInfo2.DBBlock != 0)
            {
                if (readWordInfo2.DBBlock != currentDBBlock)
                {
                    currentDBBlock = readWordInfo2.DBBlock;
                    isProcessedMakeBlockFirstAddress = true;
                    currentReadBlockList = new List<PlcReadBlock>();
                    _DicReadBlock.Add(currentDBBlock.ToString(), currentReadBlockList);
                }
            }
            else if (readWordInfo2.MemoryType != currentProcMemoryType)
            {
                currentProcMemoryType = readWordInfo2.MemoryType;
                isProcessedMakeBlockFirstAddress = true;
                currentReadBlockList = new List<PlcReadBlock>();
                _DicReadBlock.Add(readWordInfo2.MemoryType.ToString(), currentReadBlockList);
            }
            if (isProcessedMakeBlockFirstAddress)
            {
                makeBlock = new PlcReadBlock();
                makeBlock.MemoryType = currentProcMemoryType;
                makeBlock.StartAddr = readWordInfo2.StartAddr;
                makeBlock.DBBlock = readWordInfo2.DBBlock;
                currentReadBlockList.Add(makeBlock);
                isProcessedMakeBlockFirstAddress = false;
            }
            if (readWordInfo2.StartAddr + readWordInfo2.ReadCount - 1 - makeBlock.StartAddr >= readMaximumSize)
            {
                makeBlock = new PlcReadBlock();
                makeBlock.MemoryType = currentProcMemoryType;
                makeBlock.DBBlock = readWordInfo2.DBBlock;
                makeBlock.StartAddr = readWordInfo2.StartAddr;
                currentReadBlockList.Add(makeBlock);
            }
            int currentEndAddress = readWordInfo2.StartAddr + readWordInfo2.ReadCount - 1;
            if (makeBlock.EndAddr < currentEndAddress)
            {
                makeBlock.EndAddr = currentEndAddress;
            }
            makeBlock.ReadWordCount = makeBlock.EndAddr - makeBlock.StartAddr + 1;
        }
        _DicReadBlock.Values.ToList().ForEach(delegate (List<PlcReadBlock> readBlockList)
        {
            readBlockList.ForEach(delegate (PlcReadBlock readBlock)
            {
                readBlock.ReadBuffer = new byte[readBlock.ReadWordCount * 2];
            });
        });
    }

    public static bool CheckMakeReadBlock(int readMaximumSize, List<PlcReadWord> readAddressList, out string checkResult)
    {
        checkResult = "NoError";
        List<PlcReadWord> list = (from readWordInfo in readAddressList
                                   orderby readWordInfo.MemoryType, readWordInfo.StartAddr, readWordInfo.ReadCount descending
                                   select readWordInfo).ToList();
        Dictionary<PlcMemoryType, List<PlcReadBlock>> dictionary = new Dictionary<PlcMemoryType, List<PlcReadBlock>>();
        PlcMemoryType plcMemoryType = PlcMemoryType.D;
        bool flag = true;
        PlcReadBlock readBlock = null;
        bool flag2 = false;
        List<PlcReadBlock> list2 = null;
        foreach (PlcReadWord item in list)
        {
            if (item.MemoryType == PlcMemoryType.D)
            {
                checkResult = "PlcMemoryType is None";
                return false;
            }

            if (item.MemoryType != plcMemoryType)
            {
                plcMemoryType = item.MemoryType;
                flag = true;
                flag2 = false;
                list2 = new List<PlcReadBlock>();
                dictionary.Add(item.MemoryType, list2);
            }

            if (flag)
            {
                readBlock = new PlcReadBlock();
                readBlock.MemoryType = plcMemoryType;
                readBlock.StartAddr = item.StartAddr;
                list2.Add(readBlock);
                flag = false;
                flag2 = true;
            }

            if (item.StartAddr + item.ReadCount - 1 - readBlock.StartAddr >= readMaximumSize)
            {
                readBlock = new PlcReadBlock();
                readBlock.MemoryType = plcMemoryType;
                readBlock.StartAddr = item.StartAddr;
                list2.Add(readBlock);
                flag2 = true;
            }

            if (!flag2 && readBlock.EndAddr >= item.StartAddr)
            {
                checkResult = "BoundaryViolation : MemoryType[" + item.MemoryType.ToString() + "], Address[" + item.StartAddr + "]";
                return false;
            }

            int num = item.StartAddr + item.ReadCount - 1;
            if (readBlock.EndAddr < num)
            {
                readBlock.EndAddr = num;
            }

            readBlock.ReadWordCount = readBlock.EndAddr - readBlock.StartAddr + 1;
            flag2 = false;
        }

        return true;
    }

    public PlcReadBlock GetReadBlock(string memoryType, int containAddress)
    {

        if (!_DicReadBlock.ContainsKey(memoryType))
        {
            return null;
        }

        return _DicReadBlock[memoryType].FirstOrDefault((PlcReadBlock readBlock) => readBlock.CheckContainAddress(containAddress));
    }

    public List<List<PlcReadBlock>> GetAllReadBlockList()
    {
        return _DicReadBlock.Values.ToList();
    }
}
